<?php
namespace Matrix;

/**
 * 表单辅助类
 *
 * 辅助表单
 */
class Form
{
	/**
	 * 所有已经被创建了的标签
	 *
	 * @var array
	 */
	public static $labels = array();
	
	/**
	 * 自定义宏命令
	 *
	 * @var array
	 */
	public static $macros = array();
	
	/**
	 * 注册一个宏命令
	 *
	 * @param	string	$name
	 * @param	Closure	$macro
	 * @return	void
	 */
	public static function extend($name, \Closure $macro)
	{
		$this->macros[$name] = $macro;
	}
	
	/**
	 * 打开一个HTML表单
	 *
	 * @param	string	$action
	 * @param	string	$method
	 * @param	array	$attributes
	 * @param	boolean	$https
	 * @return	string
	 */
	public static function open($action = null, $method = 'POST', $attributes = array(), $https = false)
	{
		$method = strtoupper($method);
		$attributes['method'] = static::method($method);
		$attributes['action'] = static::action($action, $https);
		if (!isset($attributes['accept-charset'])) {
			$attributes['accept-charset'] = Config::get('application.encoding');
		}
		
		$append = '';
		if ($method == 'PUT' || $method == 'DELETE') {
			$append = static::hidden(Request::spoofer, $method);
		}
		return '<form'.HTML::attributes($attributes).'>'.$append;
	}
	
	/**
	 * 确定一个适当的请求方法, 支持GET和POST
	 *
	 * @param	string	$method
	 * @return	string
	 */
	protected static function method($method)
	{
		return $method !== 'GET' ? 'POST' : $method;
	}
	
	/**
	 * 确定一个适当的动作来操作表单
	 * 如果$action没有指定, 将使用当前URL
	 *
	 * @param	string	$action
	 * @param	boolean	$https
	 * @return	string
	 */
	protected static function action($action, $https)
	{
		$uri = $action === null ? URI::current() : $action;
		return HTML::entities(URL::to($uri, $https));
	}
	
	/**
	 * 打开一个HTTPS的动作的html表单
	 *
	 * @param	string|null	$action
	 * @param	string	$method
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function open_secure($action = null, $method = 'POST', $attributes = array())
	{
		return static::open($action, $method, $attributes, true);
	}
	
	/**
	 * 打开一个上传文件的HTML表单
	 *
	 * @param	string|null	$action
	 * @param	string	$method
	 * @param	array	$attributes
	 * @param	boolean	$https
	 * @return	string
	 */
	public static function open_file($action = null, $method = 'POST', $attributes = array(), $https = false)
	{
		$attributes['enctype'] = 'multipart/form-data';
		return static::open($action, $method, $attributes, $https);
	}
	
	/**
	 * 打开一个HTTPS的动作上传文件表单
	 *
	 * @param	mixed	$action
	 * @param	string	$method
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function open_secure_for_file($action = null, $method = 'POST', $attributes = array())
	{
		return static::open_file($action, $method, $attributes, true);
	}
	
	/**
	 * 关闭表单
	 *
	 * @return	string
	 */
	public static function close()
	{
		return '</form>';
	}
	
	/**
	 * 生成一个隐藏字段包含防跨站攻击的令牌
	 *
	 * @return	string
	 */
	public static function token()
	{
		return static::hidden(Session::csrf_token, Session::token());
	}
	
	/**
	 * 生成一个标签
	 *
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	void
	 */
	public static function label($name, $value, $attributes = array())
	{
		static::$labels[] = $name;
		$attributes = HTML::attributes($attributes);
		$value = HTML::entities($value);
		return '<label for="'.$name.'"'.$attributes.'>'.$value.'</label>';
	}
	
	/**
	 * 创建一个INPUT元素
	 * 
	 * @param	string	$type
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function input($type, $name, $value = null, $attributes = array())
	{
		$name = (isset($attributes['name'])) ? $attributes['name'] : $name;
		$id = static::id($name, $attributes);
		$attributes = array_merge($attributes, compact('type', 'name', 'value', 'id'));
		return '<input'.HTML::attributes($attributes).'>';
	}
	
	/**
	 * 创建一个INPUT TEXT元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function text($name, $value = null, $attributes = array())
	{
		return static::input('text', $name, $value = null, $attributes = array());
	}
	
	/**
	 * 创建一个INPUT PASSWORD元素
	 * 
	 * @param	string	$name
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function password($name, $attributes = array())
	{
		return static::input('password', $name, null, $attributes);
	}
	
	/**
	 * 创建一个INPUT HIDDEN元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function hidden($name, $value = null, $attributes = array())
	{
		return static::input('hidden', $name, $value = null, $attributes = array());
	}
	
	/**
	 * 创建一个INPUT SEARCH元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function search($name, $value = null, $attributes = array())
	{
		return static::input('search', $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT EMAIL元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function email($name, $value = null, $attributes = array())
	{
		return static::input('email', $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT TELPHONE元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function telephone($name, $value = null, $attributes = array())
	{
		return static::input('tel', $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT URL元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function url($name, $value = null, $attributes = array())
	{
		return static::input('url', $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT NUMBER元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */	
	public static function number($name, $value = null, $attributes = array())
	{
		return static::input('number', $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT DATE元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */	
	public static function date($name, $value = null, $attributes = array())
	{
		return static::input('date', $name, $value, $attributes);
	}

	/**
	 * 创建一个INPUT FILE元素
	 * 
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */	
	public static function file($name, $attributes = array())
	{
		return static::input('file', $name, null, $attributes);
	}
	
	/**
	 * 生成一个textarea元素
	 *
	 * @param	string	$name
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */	
	public static function textarea($name, $value = null, $attributes = array())
	{
		$attributes['name'] = $name;
		$attributes['id'] = static::id($name, $attributes);
		if (!isset($attributes['rows'])) {
			$attributes['rows'] = 10;
		}
		if (!isset($attributes['cols'])) {
			$attributes['cols'] = 50;
		}
		return '<textarea'.HTML::attributes($attributes).'>'.HTML::entities($value).'</textarea>';
	}
	
	/**
	 * 创建一个select元素
	 *
	 * @param	string	$name
	 * @param	array	$option
	 * @param	string	$selected
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function select($name, $options = array(), $selected = null, $attributes = array())
	{
		$attributes['name'] = $name;
		$attributes['id'] = static::id($name, $attributes);
		$html = array();
		
		foreach ($options as $value => $display) {
			if (is_array($display)) {
				$html[] = static::optgroup($display, $value, $selected);
			} else {
				$html[] = static::option($value, $display, $selected);
			}
		}
		return '<select'.HTML::attributes($attributes).'>'.implode('', $html).'</select>';
	}
	
	/**
	 * 创建一个select optgroup元素
	 *
	 * @param	array	$options
	 * @param	string	$label
	 * @param	string	$selected
	 * @return	string
	 */
	protected static function optgroup($options, $label, $selected)
	{
		$html = array();
		foreach ($options as $value => $display) {
			$html[] = static::option($value, $display, $selected);
		}
		return '<optgroup label="'.HTML::entities($label).'">'.implode('', $html).'</option>';
	}
	
	/**
	 * 创建一个select option元素
	 *
	 * @param	string	$value
	 * @param	string	$display
	 * @param	string	$selected
	 * @return	string
	 */
	protected static function option($value, $display, $selected)
	{
		if (is_array($selected)) {
			$selected = in_array($value, $selected) ? 'selected' : null;
		} else {
			$selected = $value == $selected ? 'selected' : null;
		}
		$attributes = array('value' => HTML::entities($value), 'selected' => $selected);
		return '<option'.HTML::attributes($attributes).'>'.HTML::entities($display).'</option>';
	}
	
	/**
	 * 创建一个复选框元素
	 *
	 * @param	string	$name
	 * @param	mixed	$value
	 * @param	boolean	$checed
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function checkbox($name, $value = 1, $checked = false, $attributes = array())
	{
		return static::checkable('checkbox', $name, $value, $checked, $attributes);
	}
	
	/**
	 * 创建一个单选框元素
	 *
	 * @param	string	$name
	 * @param	mixed	$value
	 * @param	boolean	$checed
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function radio($name, $value = null, $checked = false, $attributes = array())
	{
		if ($value === null) {
			$value = $name;
		}
		return static::checkable('radio', $name, $value, $checked, $attributes);
	}
	
	/**
	 * 创建一个可用的单选或者复选框
	 *
	 * @param	string	$type
	 * @param	string	$name
	 * @param	mixed	$value
	 * @param	boolean	$checed
	 * @param	array	$attributes
	 * @return	string
	 */
	protected static function checkable($type, $value = null, $checked = false, $attributes = array())
	{
		if ($checked) {
			$attributes['checked'] = 'checked';
		}
		$attributes['id'] = static::id($name, $attributes);
		return static::input($type, $name, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT SUBMIT元素
	 *
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function submit($value, $attributes = array())
	{
		return static::input('submit', null, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT RESET元素
	 *
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function reset($value, $attributes = array())
	{
		return static::input('reset', null, $value, $attributes);
	}
	
	/**
	 * 创建一个INPUT IMG元素
	 *
	 * @param	string	$url
	 * @param	string	$name
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function image($url, $name = null, $attributes = array())
	{
		$attributes['src'] = URL::to_asset($url);
		return static::input('image', $name, null, $attributes);
	}
	
	/**
	 * 创建一个BUTTON元素
	 *
	 * @param	string	$value
	 * @param	array	$attributes
	 * @return	string
	 */
	public static function button($value, $attributes = array())
	{
		return '<button'.HTML::attributes($attributes).'>'.HTML::entities($value).'</button>';
	}
	
	/**
	 * 返回ID
	 *
	 * @param	string	$name
	 * @param	array	$attributes
	 * @return	string
	 */
	protected static function id($name, $attributes)
	{
		if (isset($attributes['id'])) {
			return $attributes['id'];
		}
		if (in_array($name, static::$labels)) {
			return $name;
		}
	}
	
	/**
	 * 静态调用自定义的宏命令
	 *
	 * @param	string	$method
	 * @param	array	$parameters
	 * @return	string
	 * @throws	Exception
	 */
	public static function __callStatic($method, $parameters)
	{
		if (isset(static::$macros[$method])) {
			return call_user_func_array(static::$macros[$method], $parameters);
		}
		throw new \Exception("Method [$method] does not exist.");
	}